package com.kexio.log.analytics.service.impl;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;

import com.kexio.log.analytics.service.LogMetricsCollector;

/**
 * 日志指标收集器实现
 * 
 * 负责收集和统计日志相关的分析指标
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Service
@ConditionalOnProperty(prefix = "kexio.log.analytics", name = "enabled", havingValue = "true")
public class LogMetricsCollectorImpl implements LogMetricsCollector {
    
    private static final Logger logger = LoggerFactory.getLogger(LogMetricsCollectorImpl.class);
    
    // 总体统计
    private final AtomicLong totalMethods = new AtomicLong(0);
    private final AtomicLong totalRequests = new AtomicLong(0);
    private final AtomicLong totalExceptions = new AtomicLong(0);
    private final AtomicLong totalUserActions = new AtomicLong(0);
    
    // 按日志级别统计
    private final AtomicLong errorLogs = new AtomicLong(0);
    private final AtomicLong warnLogs = new AtomicLong(0);
    private final AtomicLong infoLogs = new AtomicLong(0);
    private final AtomicLong debugLogs = new AtomicLong(0);
    
    // 按方法统计
    private final Map<String, MethodMetrics> methodMetrics = new ConcurrentHashMap<>();
    
    // 按请求路径统计
    private final Map<String, RequestMetrics> requestMetrics = new ConcurrentHashMap<>();
    
    // 按异常类型统计
    private final Map<String, ExceptionMetrics> exceptionMetrics = new ConcurrentHashMap<>();
    
    // 用户行为统计
    private final Map<String, UserBehaviorMetrics> userBehaviorMetrics = new ConcurrentHashMap<>();
    
    // 性能统计
    private final Map<String, PerformanceMetrics> performanceMetrics = new ConcurrentHashMap<>();
    
    @Override
    public void recordMethodExecution(String className, String methodName, String layer,
                                     long executionTime, boolean isSuccess, Throwable exception) {
        try {
            totalMethods.incrementAndGet();
            
            String methodKey = className + "." + methodName;
            MethodMetrics metrics = methodMetrics.computeIfAbsent(
                methodKey, k -> new MethodMetrics(methodKey, layer)
            );
            metrics.addExecution(executionTime, isSuccess, exception);
            
            // 记录性能指标
            PerformanceMetrics perfMetrics = performanceMetrics.computeIfAbsent(
                layer, k -> new PerformanceMetrics(layer)
            );
            perfMetrics.addExecution(executionTime, isSuccess);
            
            // 记录日志级别
            if (!isSuccess && exception != null) {
                errorLogs.incrementAndGet();
            } else if (executionTime > 2000) { // 慢方法记为警告
                warnLogs.incrementAndGet();
            } else {
                infoLogs.incrementAndGet();
            }
            
            // 清理过多的方法指标 (保持在2000个以内)
            if (methodMetrics.size() > 2000) {
                cleanupMethodMetrics();
            }
            
        } catch (Exception e) {
            logger.error("记录方法执行指标失败: {}", e.getMessage(), e);
        }
    }
    
    @Override
    public void recordControllerRequest(String requestPath, String method, long responseTime,
                                       int statusCode, String userAgent, String clientIp) {
        try {
            totalRequests.incrementAndGet();
            
            String requestKey = method + " " + requestPath;
            RequestMetrics metrics = requestMetrics.computeIfAbsent(
                requestKey, k -> new RequestMetrics(requestKey)
            );
            metrics.addRequest(responseTime, statusCode, userAgent, clientIp);
            
            // 记录日志级别
            if (statusCode >= 500) {
                errorLogs.incrementAndGet();
            } else if (statusCode >= 400) {
                warnLogs.incrementAndGet();
            } else {
                infoLogs.incrementAndGet();
            }
            
            // 清理过多的请求指标
            if (requestMetrics.size() > 1000) {
                cleanupRequestMetrics();
            }
            
        } catch (Exception e) {
            logger.error("记录控制器请求指标失败: {}", e.getMessage(), e);
        }
    }
    
    @Override
    public void recordException(String className, String methodName, Throwable exception, String context) {
        try {
            totalExceptions.incrementAndGet();
            errorLogs.incrementAndGet();
            
            String exceptionType = exception.getClass().getSimpleName();
            ExceptionMetrics metrics = exceptionMetrics.computeIfAbsent(
                exceptionType, k -> new ExceptionMetrics(exceptionType)
            );
            metrics.addException(className, methodName, exception.getMessage(), context);
            
        } catch (Exception e) {
            logger.error("记录异常指标失败: {}", e.getMessage(), e);
        }
    }
    
    @Override
    public void analyzeUserBehavior(String userId, String action, String resource, LocalDateTime timestamp) {
        try {
            totalUserActions.incrementAndGet();
            
            UserBehaviorMetrics metrics = userBehaviorMetrics.computeIfAbsent(
                userId, k -> new UserBehaviorMetrics(userId)
            );
            metrics.addAction(action, resource, timestamp);
            
            // 清理过多的用户行为数据 (保持在5000个用户)
            if (userBehaviorMetrics.size() > 5000) {
                cleanupUserBehaviorMetrics();
            }
            
        } catch (Exception e) {
            logger.error("记录用户行为失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 获取总体统计
     */
    public LogOverallMetrics getOverallMetrics() {
        return new LogOverallMetrics(
            totalMethods.get(),
            totalRequests.get(),
            totalExceptions.get(),
            totalUserActions.get(),
            errorLogs.get(),
            warnLogs.get(),
            infoLogs.get(),
            debugLogs.get(),
            LocalDateTime.now()
        );
    }
    
    /**
     * 获取方法指标
     */
    public Map<String, MethodMetrics> getMethodMetrics() {
        return new ConcurrentHashMap<>(methodMetrics);
    }
    
    /**
     * 获取请求指标
     */
    public Map<String, RequestMetrics> getRequestMetrics() {
        return new ConcurrentHashMap<>(requestMetrics);
    }
    
    /**
     * 获取异常指标
     */
    public Map<String, ExceptionMetrics> getExceptionMetrics() {
        return new ConcurrentHashMap<>(exceptionMetrics);
    }
    
    /**
     * 获取用户行为指标
     */
    public Map<String, UserBehaviorMetrics> getUserBehaviorMetrics() {
        return new ConcurrentHashMap<>(userBehaviorMetrics);
    }
    
    /**
     * 获取性能指标
     */
    public Map<String, PerformanceMetrics> getPerformanceMetrics() {
        return new ConcurrentHashMap<>(performanceMetrics);
    }
    
    /**
     * 重置指标
     */
    public void resetMetrics() {
        totalMethods.set(0);
        totalRequests.set(0);
        totalExceptions.set(0);
        totalUserActions.set(0);
        errorLogs.set(0);
        warnLogs.set(0);
        infoLogs.set(0);
        debugLogs.set(0);
        
        methodMetrics.clear();
        requestMetrics.clear();
        exceptionMetrics.clear();
        userBehaviorMetrics.clear();
        performanceMetrics.clear();
        
        logger.info("日志分析指标已重置");
    }
    
    /**
     * 清理方法指标 (保留最活跃的1000个)
     */
    private void cleanupMethodMetrics() {
        try {
            methodMetrics.entrySet().stream()
                .sorted((e1, e2) -> Long.compare(e2.getValue().getTotalExecutions(), e1.getValue().getTotalExecutions()))
                .skip(1000)
                .forEach(entry -> methodMetrics.remove(entry.getKey()));
        } catch (Exception e) {
            logger.error("清理方法指标失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 清理请求指标 (保留最活跃的500个)
     */
    private void cleanupRequestMetrics() {
        try {
            requestMetrics.entrySet().stream()
                .sorted((e1, e2) -> Long.compare(e2.getValue().getTotalRequests(), e1.getValue().getTotalRequests()))
                .skip(500)
                .forEach(entry -> requestMetrics.remove(entry.getKey()));
        } catch (Exception e) {
            logger.error("清理请求指标失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 清理用户行为指标 (保留最活跃的2500个用户)
     */
    private void cleanupUserBehaviorMetrics() {
        try {
            userBehaviorMetrics.entrySet().stream()
                .sorted((e1, e2) -> Long.compare(e2.getValue().getTotalActions(), e1.getValue().getTotalActions()))
                .skip(2500)
                .forEach(entry -> userBehaviorMetrics.remove(entry.getKey()));
        } catch (Exception e) {
            logger.error("清理用户行为指标失败: {}", e.getMessage(), e);
        }
    }
    
    /**
     * 方法指标
     */
    public static class MethodMetrics {
        private final String methodName;
        private final String layer;
        private final AtomicLong totalExecutions = new AtomicLong(0);
        private final AtomicLong successfulExecutions = new AtomicLong(0);
        private final AtomicLong exceptions = new AtomicLong(0);
        private final AtomicLong totalTime = new AtomicLong(0);
        private final AtomicLong maxTime = new AtomicLong(0);
        private final AtomicLong minTime = new AtomicLong(Long.MAX_VALUE);
        private volatile LocalDateTime lastExecution = LocalDateTime.now();
        
        public MethodMetrics(String methodName, String layer) {
            this.methodName = methodName;
            this.layer = layer;
        }
        
        public void addExecution(long executionTime, boolean isSuccess, Throwable exception) {
            totalExecutions.incrementAndGet();
            totalTime.addAndGet(executionTime);
            lastExecution = LocalDateTime.now();
            
            if (isSuccess) {
                successfulExecutions.incrementAndGet();
            } else {
                exceptions.incrementAndGet();
            }
            
            maxTime.updateAndGet(val -> Math.max(val, executionTime));
            minTime.updateAndGet(val -> Math.min(val, executionTime));
        }
        
        public double getAverageTime() {
            long total = totalExecutions.get();
            return total > 0 ? (double) totalTime.get() / total : 0.0;
        }
        
        public double getSuccessRate() {
            long total = totalExecutions.get();
            return total > 0 ? (double) successfulExecutions.get() / total : 0.0;
        }
        
        // Getters
        public String getMethodName() { return methodName; }
        public String getLayer() { return layer; }
        public long getTotalExecutions() { return totalExecutions.get(); }
        public long getSuccessfulExecutions() { return successfulExecutions.get(); }
        public long getExceptions() { return exceptions.get(); }
        public long getMaxTime() { return maxTime.get(); }
        public long getMinTime() { return minTime.get() == Long.MAX_VALUE ? 0 : minTime.get(); }
        public LocalDateTime getLastExecution() { return lastExecution; }
    }
    
    /**
     * 请求指标
     */
    public static class RequestMetrics {
        private final String requestPath;
        private final AtomicLong totalRequests = new AtomicLong(0);
        private final AtomicLong successfulRequests = new AtomicLong(0);
        private final AtomicLong clientErrors = new AtomicLong(0);
        private final AtomicLong serverErrors = new AtomicLong(0);
        private final AtomicLong totalResponseTime = new AtomicLong(0);
        private final AtomicLong maxResponseTime = new AtomicLong(0);
        private final Map<String, AtomicLong> userAgents = new ConcurrentHashMap<>();
        private final Map<String, AtomicLong> clientIps = new ConcurrentHashMap<>();
        
        public RequestMetrics(String requestPath) {
            this.requestPath = requestPath;
        }
        
        public void addRequest(long responseTime, int statusCode, String userAgent, String clientIp) {
            totalRequests.incrementAndGet();
            totalResponseTime.addAndGet(responseTime);
            maxResponseTime.updateAndGet(val -> Math.max(val, responseTime));
            
            if (statusCode < 400) {
                successfulRequests.incrementAndGet();
            } else if (statusCode < 500) {
                clientErrors.incrementAndGet();
            } else {
                serverErrors.incrementAndGet();
            }
            
            // 统计用户代理和IP (限制数量避免内存泄漏)
            if (userAgent != null && userAgents.size() < 100) {
                userAgents.computeIfAbsent(userAgent, k -> new AtomicLong(0)).incrementAndGet();
            }
            if (clientIp != null && clientIps.size() < 1000) {
                clientIps.computeIfAbsent(clientIp, k -> new AtomicLong(0)).incrementAndGet();
            }
        }
        
        public double getAverageResponseTime() {
            long total = totalRequests.get();
            return total > 0 ? (double) totalResponseTime.get() / total : 0.0;
        }
        
        public double getSuccessRate() {
            long total = totalRequests.get();
            return total > 0 ? (double) successfulRequests.get() / total : 0.0;
        }
        
        // Getters
        public String getRequestPath() { return requestPath; }
        public long getTotalRequests() { return totalRequests.get(); }
        public long getSuccessfulRequests() { return successfulRequests.get(); }
        public long getClientErrors() { return clientErrors.get(); }
        public long getServerErrors() { return serverErrors.get(); }
        public long getMaxResponseTime() { return maxResponseTime.get(); }
        public Map<String, AtomicLong> getUserAgents() { return userAgents; }
        public Map<String, AtomicLong> getClientIps() { return clientIps; }
    }
    
    /**
     * 异常指标
     */
    public static class ExceptionMetrics {
        private final String exceptionType;
        private final AtomicLong totalOccurrences = new AtomicLong(0);
        private final Map<String, AtomicLong> methodOccurrences = new ConcurrentHashMap<>();
        private final Map<String, AtomicLong> messageOccurrences = new ConcurrentHashMap<>();
        private volatile LocalDateTime lastOccurrence = LocalDateTime.now();
        private volatile String lastMessage = "";
        
        public ExceptionMetrics(String exceptionType) {
            this.exceptionType = exceptionType;
        }
        
        public void addException(String className, String methodName, String message, String context) {
            totalOccurrences.incrementAndGet();
            lastOccurrence = LocalDateTime.now();
            lastMessage = message != null ? message : "";
            
            String methodKey = className + "." + methodName;
            methodOccurrences.computeIfAbsent(methodKey, k -> new AtomicLong(0)).incrementAndGet();
            
            if (message != null && messageOccurrences.size() < 50) {
                messageOccurrences.computeIfAbsent(message, k -> new AtomicLong(0)).incrementAndGet();
            }
        }
        
        // Getters
        public String getExceptionType() { return exceptionType; }
        public long getTotalOccurrences() { return totalOccurrences.get(); }
        public Map<String, AtomicLong> getMethodOccurrences() { return methodOccurrences; }
        public Map<String, AtomicLong> getMessageOccurrences() { return messageOccurrences; }
        public LocalDateTime getLastOccurrence() { return lastOccurrence; }
        public String getLastMessage() { return lastMessage; }
    }
    
    /**
     * 用户行为指标
     */
    public static class UserBehaviorMetrics {
        private final String userId;
        private final AtomicLong totalActions = new AtomicLong(0);
        private final Map<String, AtomicLong> actionCounts = new ConcurrentHashMap<>();
        private final Map<String, AtomicLong> resourceCounts = new ConcurrentHashMap<>();
        private volatile LocalDateTime lastAction = LocalDateTime.now();
        private volatile LocalDateTime firstAction = LocalDateTime.now();
        
        public UserBehaviorMetrics(String userId) {
            this.userId = userId;
        }
        
        public void addAction(String action, String resource, LocalDateTime timestamp) {
            totalActions.incrementAndGet();
            lastAction = timestamp;
            
            if (actionCounts.isEmpty()) {
                firstAction = timestamp;
            }
            
            if (action != null && actionCounts.size() < 50) {
                actionCounts.computeIfAbsent(action, k -> new AtomicLong(0)).incrementAndGet();
            }
            if (resource != null && resourceCounts.size() < 100) {
                resourceCounts.computeIfAbsent(resource, k -> new AtomicLong(0)).incrementAndGet();
            }
        }
        
        // Getters
        public String getUserId() { return userId; }
        public long getTotalActions() { return totalActions.get(); }
        public Map<String, AtomicLong> getActionCounts() { return actionCounts; }
        public Map<String, AtomicLong> getResourceCounts() { return resourceCounts; }
        public LocalDateTime getLastAction() { return lastAction; }
        public LocalDateTime getFirstAction() { return firstAction; }
    }
    
    /**
     * 性能指标
     */
    public static class PerformanceMetrics {
        private final String layer;
        private final AtomicLong totalExecutions = new AtomicLong(0);
        private final AtomicLong totalTime = new AtomicLong(0);
        private final AtomicLong successfulExecutions = new AtomicLong(0);
        private final AtomicLong slowExecutions = new AtomicLong(0); // > 1秒
        
        public PerformanceMetrics(String layer) {
            this.layer = layer;
        }
        
        public void addExecution(long executionTime, boolean isSuccess) {
            totalExecutions.incrementAndGet();
            totalTime.addAndGet(executionTime);
            
            if (isSuccess) {
                successfulExecutions.incrementAndGet();
            }
            
            if (executionTime > 1000) {
                slowExecutions.incrementAndGet();
            }
        }
        
        public double getAverageTime() {
            long total = totalExecutions.get();
            return total > 0 ? (double) totalTime.get() / total : 0.0;
        }
        
        public double getSuccessRate() {
            long total = totalExecutions.get();
            return total > 0 ? (double) successfulExecutions.get() / total : 0.0;
        }
        
        public double getSlowRate() {
            long total = totalExecutions.get();
            return total > 0 ? (double) slowExecutions.get() / total : 0.0;
        }
        
        // Getters
        public String getLayer() { return layer; }
        public long getTotalExecutions() { return totalExecutions.get(); }
        public long getSuccessfulExecutions() { return successfulExecutions.get(); }
        public long getSlowExecutions() { return slowExecutions.get(); }
    }
    
    /**
     * 总体指标
     */
    public static class LogOverallMetrics {
        private final long totalMethods;
        private final long totalRequests;
        private final long totalExceptions;
        private final long totalUserActions;
        private final long errorLogs;
        private final long warnLogs;
        private final long infoLogs;
        private final long debugLogs;
        private final LocalDateTime timestamp;
        
        public LogOverallMetrics(long totalMethods, long totalRequests, long totalExceptions,
                               long totalUserActions, long errorLogs, long warnLogs, long infoLogs,
                               long debugLogs, LocalDateTime timestamp) {
            this.totalMethods = totalMethods;
            this.totalRequests = totalRequests;
            this.totalExceptions = totalExceptions;
            this.totalUserActions = totalUserActions;
            this.errorLogs = errorLogs;
            this.warnLogs = warnLogs;
            this.infoLogs = infoLogs;
            this.debugLogs = debugLogs;
            this.timestamp = timestamp;
        }
        
        public long getTotalLogs() {
            return errorLogs + warnLogs + infoLogs + debugLogs;
        }
        
        public double getErrorRate() {
            long total = getTotalLogs();
            return total > 0 ? (double) errorLogs / total : 0.0;
        }
        
        // Getters
        public long getTotalMethods() { return totalMethods; }
        public long getTotalRequests() { return totalRequests; }
        public long getTotalExceptions() { return totalExceptions; }
        public long getTotalUserActions() { return totalUserActions; }
        public long getErrorLogs() { return errorLogs; }
        public long getWarnLogs() { return warnLogs; }
        public long getInfoLogs() { return infoLogs; }
        public long getDebugLogs() { return debugLogs; }
        public LocalDateTime getTimestamp() { return timestamp; }
    }
}
